home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / UNIX.ZIP / VMSCRACK / HPWD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-14  |  18.6 KB  |  740 lines

  1. /*
  2.  
  3. Title:    LGIHPWD
  4. Author:   Shawn A. Clifford (sysop@robot.nuceng.ufl.edu)
  5. Date:     19-FEB-1993
  6. Purpose:  Portable C version of the last 3 encryption methods for DEC's
  7.           password hashing algorithms.
  8.  
  9. Usage:    status = lgihpwd(&out_buf,&pwd_buf,encrypt,salt,&unam_buf);
  10.  
  11.           int lgihpwd(dscdescriptor *output_hash,
  12.                       dscdescriptor *password,
  13.                       int encrypt,
  14.                       word salt,
  15.                       dscdescriptor *username)
  16.  
  17.           Where:
  18.                       output_hash = 8 byte output buffer descriptor
  19.                          password = n character password string descriptor
  20.                           encrypt = 1 byte; value determines algorithm to use
  21.                                     0 -> CRC algorithm   (not supported)
  22.                                     1 -> Purdy algorithm
  23.                                     2 -> Purdy_V
  24.                                     3 -> Purdy_S (Hickory algorithm)
  25.                              salt = 2 byte random number
  26.                          username = up to 31 character username descriptor
  27. */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include "mytypes.h"
  33. #include "hpwd.h"
  34.  
  35. /* 2^64 - 59 is the biggest quadword prime */
  36.  
  37. #define A 59
  38. #define P_D_LOW  (DWORD_MAX-A+1UL)
  39. #define P_D_HIGH DWORD_MAX
  40.  
  41. /* These exponents are prime, but this is      */
  42. /* not required by the algorithm               */
  43. /* N0 = 2^24 - 3;  N1 = 2^24 - 63;  N0-N1 = 60 */
  44.  
  45. #define N0 0xFFFFFDUL
  46. #define N1 0xFFFFC1UL
  47.  
  48. #define MASK 0x7  /* mask for COLLAPSE_R2 */
  49.  
  50. /************
  51.    PQMOD_R0
  52.  ************/
  53.  
  54. /*
  55.    U : output buffer (quadword)
  56.  
  57.    This routine replaces the quadword U with U MOD P, where P is of the form
  58.    P = 2^64 - a                    (RELATIVELY GLOBAL a = 59)
  59.      = FFFFFFFF.FFFFFFFF - 3B + 1  (DWORD_MAX = FFFFFFFF = 4,294,967,295)
  60.      = FFFFFFFF.FFFFFFC5
  61.  
  62.    Method:  Since P is very nearly the maximum integer you can specify in a
  63.    quadword (ie. P = FFFFFFFFFFFFFFC5, there will be only 58 choices for
  64.    U that are larger than P (ie. U MOD P > 0).  So we check the high longword
  65.    in the quadword and see if all its bits are set (-1).  If not, then U can
  66.    not possibly be larger than P, and U MOD P = U.  If U is larger than
  67.    DWORD_MAX - 59,then U MOD P is the differential between (DWORD_MAX - 59)
  68.    and U, else U MOD P = U. If U equals P, then U MOD P = 0 = (P + 59).
  69.  
  70.    Optimized by Mario Ambrogetti
  71.  
  72. */
  73.  
  74. #define PQMOD_R0(U) if ((U).d_high==P_D_HIGH && (U).d_low>=P_D_LOW) {  \
  75.                       (U).d_low+=A;(U).d_high=0UL;}
  76.  
  77. /** Function prototypes **/
  78.  
  79. #ifdef USE386
  80.  
  81.   #define NO_EMULQ
  82.   #define NO_PQADD_R0
  83.  
  84.   #ifdef __WATCOMC__
  85.  
  86.     #define USE_QROL1
  87.  
  88.     #pragma aux QROL1 = 0xD1 0x00       /* rol dword ptr [eax],1   */  \
  89.                         0xD1 0x40 0x04  /* rol dword ptr [eax+4],1 */  \
  90.                         parm [eax];
  91.  
  92.     #pragma aux EMULQ = 0xF7 0xE2        /* mul  edx         */  \
  93.                         0x89 0x03        /* mov  [ebx],eax   */  \
  94.                         0x89 0x53 0x04   /* mov  [ebx+4],edx */  \
  95.                         parm [eax] [edx] [ebx] modify [eax edx];
  96.  
  97.     #pragma aux PQADD_R0 = 0x8B 0x03        /* mov  eax,[ebx]   */  \
  98.                            0x8B 0x53 0x04   /* mov  edx,[ebx+4] */  \
  99.                            0x03 0x01        /* add  eax,[ecx]   */  \
  100.                            0x13 0x51 0x04   /* adc  edx,[ecx+4] */  \
  101.                            0x73 0x06        /* jnc  NC          */  \
  102.                            0x83 0xC0 A      /* add  eax,A       */  \
  103.                            0x83 0xD2 0x00   /* adc  edx,0       */  \
  104.                            0x89 0x06        /* NC:mov [esi],eax */  \
  105.                            0x89 0x56 0x04   /* mov  [esi+4],edx */  \
  106.                            parm [ebx] [ecx] [esi] modify [eax edx];
  107.  
  108.   #elif defined(__BORLANDC__)
  109.  
  110.     #define USE_EMULQ_386
  111.     #define USE_PQADD_R0_386
  112.  
  113.     #define EMULQ    emulq_386
  114.     #define PQADD_R0 pqadd_r0_386
  115.  
  116.     static void emulq_386(dword,dword,qword *);
  117.     static void pqadd_r0_386(qword *,qword *,qword *);
  118.  
  119.   #else
  120.  
  121.     #error Error USE386
  122.  
  123.   #endif
  124.  
  125. #else
  126.  
  127.   #define EMULQ    emulq
  128.   #define PQADD_R0 pqadd_r0
  129.  
  130.   static void emulq(dword,dword,qword *);           /* (a * b)       */
  131.   static void pqadd_r0(qword *,qword *,qword *);    /* (U + Y) MOD P */
  132.  
  133. #endif
  134.  
  135. static void COLLAPSE_R2(dscdescriptor *,char *,int);
  136. static void Purdy(qword *);
  137.  
  138.  
  139.  
  140.  
  141.  
  142. static void PQEXP_R3 (qword *U,
  143.                       unsigned long n,
  144.                       qword *result);            /* U^n MOD P     */
  145. static void PQMUL_R2 (qword *U,
  146.                       qword *Y,
  147.                       qword *result);            /* U * Y MOD P   */
  148. static void PQLSH_R0 (qword *U,
  149.                       qword *result);            /* 2^32*U MOD P  */
  150.  
  151. /** RELATIVELY GLOBAL variables **/
  152.  
  153. /*
  154.  *   The following table of coefficients is used by the Purdy polynmial
  155.  *   algorithm.  They are prime, but the algorithm does not require this.
  156.  */
  157.  
  158. static qword C1={0xFFFFFFADUL,0xFFFFFFFFUL};
  159. static qword C2={0xFFFFFF4DUL,0xFFFFFFFFUL};
  160. static qword C3={0xFFFFFEFFUL,0xFFFFFFFFUL};
  161. static qword C4={0xFFFFFEBDUL,0xFFFFFFFFUL};
  162. static qword C5={0xFFFFFE95UL,0xFFFFFFFFUL};
  163.  
  164. /** LGIHPWD entry point **/
  165.  
  166. /*  Optimized by Mario Ambrogetti */
  167.  
  168. void lgihpwd(dscdescriptor *output_hash,
  169.              dscdescriptor *password,
  170.              int encrypt,
  171.              word salt,
  172.              dscdescriptor *username)
  173. {
  174.   static qword   *U;          /* Points to start of output buffer   */
  175.   static qword   *r4;         /* Address of the output buffer       */
  176.   static int      r7;         /* Flag for encryption method # 3     */
  177.   char   uname[13];
  178.  
  179.   /* Setup pointer references */
  180.  
  181.   U=r4=(qword *)output_hash->dsca_pointer;
  182.   r7=(encrypt==3);
  183.  
  184.   /* Clear the output buffer (zero the quadword) */
  185.  
  186.   U->d_low=U->d_high=0UL;
  187.  
  188.   switch (encrypt) {
  189.  
  190.     /* CRC algorithm with Autodin II poly */
  191.  
  192.     case UAIC_AD_II:
  193.  
  194.       /* As yet unsupported */
  195.  
  196.       return;
  197.  
  198.     /* Purdy algorithm */
  199.  
  200.     case UAIC_PURDY:
  201.  
  202.       /* Use a blank padded username */
  203.  
  204.       strcpy(uname,"            ");
  205.       strncpy(uname,username->dsca_pointer,username->dscw_length);
  206.       username->dsca_pointer=uname;
  207.       username->dscw_length=12;
  208.  
  209.       break;
  210.  
  211.     /* Purdy with blanks stripped               */
  212.     /* Hickory algorithm; Purdy_V with rotation */
  213.  
  214.     case UAIC_PURDY_V:
  215.     case UAIC_PURDY_S:
  216.  
  217.       /* If Purdy_S:  Bytes 0-1 => plaintext length */
  218.  
  219.       if (r7)
  220.         U->d_low=password->dscw_length;
  221.  
  222.     break;
  223.  
  224.   }  /* switch */
  225.  
  226.   /* Collapse the password to a quadword U; buffer pointed to by r4 */
  227.   /* password already points to password descriptor                 */
  228.  
  229.   COLLAPSE_R2(password,(char *)r4,r7);
  230.  
  231.   /* Add random salt into the middle of U                                     */
  232.  
  233.   *(word *)(((char *)r4)+3)+=salt;
  234.  
  235.   /* Collapse the username into the quadword point */
  236.   /* password to the valid username desriptor      */
  237.  
  238.   COLLAPSE_R2(username,(char *)r4,r7);
  239.  
  240.   /* Run U through the polynomial mod P */
  241.  
  242.   Purdy(U);
  243.  
  244. } /* LGIHPWD */
  245.  
  246. /***************
  247.    COLLAPSE_R2
  248.  ***************/
  249.  
  250. /*
  251.    r3 :  input string descriptor
  252.    r4 :  output buffer (quadword)
  253.    r7 :  flag (1) if using Hickory method (encrypt = 3)
  254.  
  255.    This routine takes a string of bytes (the descriptor for which is pointed
  256.    to by r3) and collapses them into a quadword (pointed to by r4).  It does
  257.    this by cycling around the bytes of the output buffer adding in the bytes
  258.    of the input string.  Additionally, after every 8 characters, each
  259.    longword in the resultant hash is rotated by one bit (PURDY_S only).
  260.  
  261.    Optimized by Mario Ambrogetti
  262. */
  263.  
  264. static void COLLAPSE_R2(dscdescriptor *r3,char *r4,int r7)
  265. {
  266. #ifndef USE_QROL1
  267.  
  268.   register dword tmp;
  269.   register dword rotate;
  270.  
  271. #endif
  272.  
  273.   int r0;
  274.   int r1;
  275.   char *r2;
  276.  
  277. /* ------------------------------------------------------------------------- */
  278.  
  279.   r0=r3->dscw_length;  /* Obtain the number of input bytes */
  280.  
  281.   /* Loop until input string exhausted */
  282.  
  283.   for (r2=r3->dsca_pointer;r0!=0;r0--) {
  284.  
  285.     *(r4+(r1=r0 & MASK))+=*r2++;
  286.  
  287.     /* If Purdy_S and last byte ... */
  288.  
  289.     if (r7 && (r1==7)) {
  290.  
  291. #ifdef USE_QROL1
  292.  
  293.       QROL1((dword *)r4);
  294. #else
  295.       /* Rotate first longword one bit */
  296.  
  297.       rotate=((tmp=((qword *)r4)->d_low)>>31) & 1;
  298.       ((qword *)r4)->d_low=(tmp<<1) | rotate;
  299.  
  300.       /* Rotate second longword one bit */
  301.  
  302.       rotate=((tmp=((qword *)r4)->d_high)>>31) & 1;
  303.       ((qword *)r4)->d_high=(tmp<<1) | rotate;
  304.  
  305. #endif
  306.  
  307.     } /* if Purdy_S */
  308.  
  309.   } /* for loop */
  310.  
  311. } /* COLLAPSE_R2 */
  312.  
  313. /*********
  314.    Purdy
  315.  *********/
  316.  
  317. /*
  318.    U : output buffer (quadword)
  319.  
  320.    This routine computes  f(U) = p(U) MOD P.  Where P is a prime of the form
  321.    P = 2^64 - a.  The function p is the following polynomial:
  322.  
  323.                    X^n0 + X^n1*C1 + X^3*C2 + X^2*C3 + X*C4 + C5
  324.                    ^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  325.                        part1                 part2
  326.  
  327.    Note:  Part1 is calculated by its congruence  (X^(n0-n1) + C1)*X^n1
  328.           finding X^n1, X^(n0-n1), X^(n0-n1)+C1, then
  329.           (X^(n0-n1) + C1)*X^n1  which equals  X^n0 + X^n1*C1
  330.  
  331.    The input U is an unsigned quadword.
  332. */
  333.  
  334. static void Purdy(qword *U)
  335. {
  336.   qword X;                /* The variable X in the polynomial            */
  337.   qword stack;            /* Returned quadword on stack                  */
  338.   qword part1;            /* Collect the polynomial ...                  */
  339.   qword part2;            /* ... in two parts                            */
  340.  
  341. /* ------------------------------------------------------------------------- */
  342.  
  343.   /* Ensure U less than P by taking U MOD P  */
  344.   /* Save copy of result:  X = U MOD P       */
  345.  
  346.   X.d_low =U->d_low;
  347.   X.d_high=U->d_high;
  348.  
  349.   PQMOD_R0(X);                          /* Make sure U is less than P   */
  350.  
  351.   PQEXP_R3 (&X, N1, &stack);            /* Calculate X^N1               */
  352.  
  353.   PQEXP_R3 (&X, (N0-N1), &part1);       /* Calculate X^(N0-N1)          */
  354.  
  355.   PQADD_R0(&part1,&C1,&part2);          /* X^(n0-n1) + C1               */
  356.  
  357.   PQMUL_R2 (&stack, &part2, &part1);    /* X^n0 + X^n1*C1               */
  358.  
  359.   /* Part 1 complete */
  360.  
  361.   PQMUL_R2(&X,&C2,&stack);              /* X*C2                         */
  362.  
  363.   PQADD_R0(&stack,&C3,&part2);          /* X*C2 + C3                    */
  364.  
  365.   PQMUL_R2 (&X, &part2, &stack);        /* X^2*C2 + X*C3                */
  366.  
  367.   PQADD_R0(&stack,&C4,&part2);          /* X^2*C2 + X*C3 + C4           */
  368.  
  369.   PQMUL_R2 (&X, &part2, &stack);        /* X^3*C2 + X^2*C3 + X*C4       */
  370.  
  371.   PQADD_R0(&stack,&C5,&part2);          /* X^3*C2 + X^2*C3 + X*C4 + C5  */
  372.  
  373.   /* Part 2 complete */
  374.  
  375.  
  376.   /* Add in the high order terms.  Replace U with f(x) */
  377.  
  378.   PQADD_R0(&part1,&part2,U);
  379.  
  380. } /* Purdy */
  381.  
  382.  
  383. /*********
  384.    EMULQ
  385.  *********/
  386.  
  387. /*
  388.    a, b   : longwords that we want to multiply (quadword result)
  389.    result : the quadword result
  390.  
  391.    This routine knows how to multiply two unsigned longwords, returning the
  392.    unsigned quadword product.
  393.  
  394.    Optimized by Mario Ambrogetti
  395. */
  396.  
  397. #ifndef NO_EMULQ
  398.  
  399. static void emulq(dword a,dword b,qword *result)
  400. {
  401.   register dword temp;
  402.  
  403.   /* c->d_low=a.w_low*b.w_low */
  404.  
  405.   result->d_low =(dword)(((dword_t *)&a)->w_low)  * (dword)(((dword_t *)&b)->w_low);
  406.  
  407.   /* c->d_high=a.w_high*b.w_high */
  408.  
  409.   result->d_high=(dword)(((dword_t *)&a)->w_high) * (dword)(((dword_t *)&b)->w_high);
  410.  
  411.   /* temp=a.w_high*b.w_low */
  412.  
  413.   temp=(dword)(((dword_t *)&a)->w_high) * (dword)(((dword_t *)&b)->w_low);
  414.  
  415.   /* checking for carry out */
  416.  
  417.   if (~temp<((qword_t *)result)->l_mid)
  418.     ((qword_t *)result)->w3++;
  419.  
  420.   /* c->>l_mid=c->>l_mid+a.w_high*b.w_low */
  421.  
  422.   ((qword_t *)result)->l_mid+=temp;
  423.  
  424.   /* temp=a.w_low*b.w_high */
  425.  
  426.   temp=(dword)(((dword_t *)&a)->w_low) * (dword)(((dword_t *)&b)->w_high);
  427.  
  428.   /* checking for carry out */
  429.  
  430.   if (~temp<((qword_t *)result)->l_mid)
  431.     ((qword_t *)result)->w3++;
  432.  
  433.   /* c->>l_mid=c->>l_mid+a.w_low*b.w_high */
  434.  
  435.   ((qword_t *)result)->l_mid+=temp;
  436.  
  437. } /* EMULQ */
  438.  
  439. #endif /* NO_EMULQ */
  440.  
  441. #ifdef USE_EMULQ_386
  442.  
  443. static void emulq_386(dword a,dword b,qword *c)
  444. {
  445.   asm {
  446.  
  447.     db 0x66
  448.     mov   ax,word ptr [a]      /* mov eax,dword ptr [a] */
  449.  
  450.     db 0x66
  451.     mul   word ptr [b]         /* mul dword ptr [b] */
  452.  
  453. #if __HUGE__ || __LARGE__ || __COMPACT__
  454.     les   bx,[c]
  455.  
  456.     db 0x66
  457.     mov   es:[bx],ax           /* mov es:[bx],eax */
  458.  
  459.     db 0x66
  460.     mov   es:[bx+4],dx         /* mov es:[bx+4],edx */
  461. #else
  462.     mov   bx,[c]
  463.  
  464.     db 0x66
  465.     mov   [bx],ax              /* mov [bx],eax */
  466.  
  467.     db 0x66
  468.     mov   [bx+4],dx            /* mov [bx+4],edx */
  469. #endif
  470.  
  471.   }
  472. }
  473.  
  474. #endif /* USE_EMULQ_386 */
  475.  
  476. /************
  477.    PQEXP_R3
  478.  ************/
  479.  
  480. static void PQEXP_R3 (qword *U, unsigned long n,qword *result)
  481. /*
  482. U     : pointer to output buffer (quadword)
  483. n     : unsigned longword (exponent for U)
  484.  
  485. The routine returns U^n MOD P where P is of the form P = 2^64-a.
  486. U is a quadword, n is an unsigned longword, P is a RELATIVELY GLOBAL quad.
  487.  
  488. The method comes from Knuth, "The Art of Computer Programing, Vol. 2", section
  489. 4.6.3, "Evaluation of Powers."  This algorithm is for calculating U^n with
  490. fewer than (n-1) multiplies.  The result is U^n MOD P only because the
  491. multiplication routine is MOD P.  Knuth's example is from Pingala's Hindu
  492. algorthim in the Chandah-sutra.
  493. */
  494.  
  495. {
  496.   qword Y, Z, Z1;     /* Intermediate factors for U */
  497.   dword odd;          /* Test for n odd/even        */
  498.  
  499.   /* Initialize */
  500.  
  501.   Y.d_low =1UL;   /* Y = 1 */
  502.   Y.d_high=0UL;
  503.  
  504.   Z = *U;
  505.  
  506.   /* Loop until n is zero */
  507.  
  508.   while (n != 0) {
  509.  
  510.     /* Test n */
  511.  
  512.     odd = n & 1;
  513.  
  514.     /* Halve n */
  515.  
  516.     n>>=1;
  517.  
  518.     /* If n was odd, then we need an extra x (U) */
  519.  
  520.     if (odd)     /* n was odd */ {
  521.  
  522.       PQMUL_R2 (&Y, &Z, result);
  523.  
  524.       if (n == 0)
  525.         return;                 /* This is the stopping condition */
  526.                                 /* Disregard the exponent, which  */
  527.                                 /* would be the final Z^2.        */
  528.       Y = *result;              /* Copy for next pass */
  529.     }
  530.  
  531.     /* Square Z; this squares the current power for Z */
  532.  
  533.     Z1.d_low =Z.d_low;
  534.     Z1.d_high=Z.d_high;
  535.  
  536.     PQMUL_R2 (&Z1, &Z1, &Z);
  537.  
  538.   }
  539.  
  540. } /* PQEXP_R3 */
  541.  
  542.  
  543.  
  544. /************
  545.    PQMUL_R2
  546.  ************/
  547.  
  548. static void PQMUL_R2 (qword *U, qword *Y, qword *result)
  549.  
  550. /*
  551. U, Y : quadwords we want to multiply
  552.  
  553. Computes the product U*Y MOD P where P is of the form P = 2^64 - a.
  554. U, Y are quadwords less than P.  The product replaces U and Y on the stack.
  555.  
  556. The product may be formed as the sum of four longword multiplications
  557. which are scaled by powers of 2^32 by evaluating:
  558.  
  559.         2^64*v*z + 2^32*(v*y + u*z) + u*y
  560.         ^^^^^^^^   ^^^^^^^^^^^^^^^^   ^^^
  561.         part1      part2 & part3      part4
  562.  
  563. The result is computed such that division by the modulus P is avoided.
  564.  
  565. u is the low longword of  U;    u = U.l_low
  566. v is the high longword of U;    v = U.l_high
  567. y is the low longword of  Y;    y = Y.l_low
  568. z is the high longword of Y;    z = Y.l_high
  569. */
  570.  
  571. {
  572.   qword stack;
  573.   qword part1;
  574.   qword part2;
  575.   qword part3;
  576.  
  577.   EMULQ(U->d_high,Y->d_high,&stack);        /* Multiply   v*z      */
  578.  
  579.   PQMOD_R0(stack);                          /* Get   (v*z) MOD P   */
  580.  
  581.   /*** 1st term ***/
  582.  
  583.   PQLSH_R0(&stack, &part1);                 /* Get   2^32*(v*z) MOD P  */
  584.  
  585.   EMULQ(U->d_high,Y->d_low,&stack);         /* Multiply   v*y      */
  586.  
  587.   PQMOD_R0(stack);                          /* Get   (v*y) MOD P   */
  588.  
  589.   EMULQ(U->d_low,Y->d_high,&part2);         /* Multiply   u*z      */
  590.  
  591.   PQMOD_R0(part2);                          /* Get   (u*z) MOD P   */
  592.  
  593.   PQADD_R0(&stack,&part2,&part3);           /* Get   (v*y + u*z)   */
  594.  
  595.   PQADD_R0(&part1,&part3,&stack);           /* Get   2^32*(v*z) + (v*y + u*z) */
  596.  
  597.   /*** 1st & 2nd terms ***/
  598.  
  599.   PQLSH_R0(&stack, &part1);       /* Get   2^64*(v*z) + 2^32*(v*y + u*z) */
  600.  
  601.   EMULQ(U->d_low,Y->d_low,&stack);          /* Multiply   u*y      */
  602.  
  603.   /*** Last term ***/
  604.  
  605.   PQMOD_R0(stack);
  606.  
  607.   PQADD_R0(&part1,&stack,result);           /* Whole thing */
  608.  
  609. } /* PQMUL_R2 */
  610.  
  611.  
  612.  
  613. /************
  614.    PQLSH_R0
  615.  ************/
  616.  
  617. static void PQLSH_R0 (qword *U, qword *result)
  618.  
  619. /*
  620. Computes the product 2^32*U MOD P where P is of the form P = 2^64 - a.
  621. U is a quadword less than P.
  622.  
  623. This routine is used by PQMUL in the formation of quadword products in
  624. such a way as to avoid division by modulus the P.
  625. The product 2^64*v + 2^32*u is congruent a*v + 2^32*U MOD P.
  626.  
  627. u is the low longword in U
  628. v is the high longword in U
  629. */
  630.  
  631. {
  632.   qword stack;
  633.  
  634.   /* Get  a*v   */
  635.  
  636.   EMULQ(U->d_high,A,&stack);
  637.  
  638.   /* Form  Y = 2^32*u  */
  639.  
  640.   U->d_high=U->d_low;
  641.   U->d_low =0UL;
  642.  
  643.   /* Get  U + Y MOD P  */
  644.  
  645.   PQADD_R0(U,&stack,result);
  646.  
  647. } /* PQLSH_R0 */
  648.  
  649.  
  650. /************
  651.    PQADD_R0
  652.  ************/
  653.  
  654. /*
  655.    U, Y : quadwords that we want to add
  656.  
  657.  
  658.    Computes the sum (U + Y) MOD P where P is of the form P = 2^64 - a.
  659.    U, Y are quadwords less than P.
  660.  
  661.    Fixed with the help of the code written by Terence Lee (DEC/HKO).
  662.  
  663.    Optimized by Mario Ambrogetti
  664. */
  665.  
  666. #ifndef NO_PQADD_R0
  667.  
  668. static void pqadd_r0(qword *U,qword *Y,qword *result)
  669. {
  670.   register dword carry;
  671.  
  672.   /* Add the low longwords */
  673.  
  674.   result->d_low=U->d_low+Y->d_low;
  675.  
  676.   /* Add the high longwords, checking for carry out */
  677.  
  678.   result->d_high=U->d_high+Y->d_high+(carry=(~U->d_low<Y->d_low ));
  679.  
  680.   /* Check if we have to MOD P the result */
  681.  
  682.   if ((~U->d_high >= (Y->d_high+carry)) && (Y->d_high != DWORD_MAX))
  683.     return;      /* Outta here? */
  684.  
  685.   result->d_low +=A;               /* U + Y MOD P */
  686.   result->d_high+=(Y->d_low > ~A);
  687.  
  688. } /* PQADD_R0 */
  689.  
  690. #endif /* NO_PQADD_R0 */
  691.  
  692. #ifdef USE_PQADD_R0_386
  693.  
  694. static void pqadd_r0_386(qword *U,qword *Y,qword *result)
  695. {
  696.   asm {
  697.  
  698.     mov bx,[U]
  699.  
  700.     db 0x66
  701.     mov   ax,[bx]              /* mov eax,[bx] */
  702.  
  703.     db 0x66
  704.     mov   dx,[bx+4]            /* mov edx,[bx+4] */
  705.  
  706.     mov   bx,[Y]
  707.  
  708.     db 0x66
  709.     add   ax,[bx]              /* add eax,[bx] */
  710.  
  711.     db 0x66
  712.     adc   dx,[bx+4]            /* adc edx,[bx+4] */
  713.  
  714.     jnc   NoCarry
  715.  
  716.     db 0x66
  717.     add   ax,A
  718.     dw 0x0000                  /* add eax,A */
  719.  
  720.     db 0x66
  721.     adc   dx,0x0000            /* adc edx,0 */
  722.  
  723.   }
  724.  
  725. NoCarry:
  726.  
  727.   asm {
  728.  
  729.     mov   bx,[result]
  730.  
  731.     db 0x66
  732.     mov   [bx],ax              /* mov [bx],eax */
  733.  
  734.     db 0x66
  735.     mov   [bx+4],dx            /* mov [bx+4],edx */
  736.   }
  737. }
  738.  
  739. #endif /* USE_PQADD_R0_386 */
  740.